<!DOCTYPE html>
<html lang=zh>
<head>
    <meta charset="utf-8">
    
    <title>Activiti工作流引擎使用 | LErry</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    <meta name="description" content="Activiti工作流引擎使用1.简单介工作流引擎与Activiti对于工作流引擎的解释请参考百度百科：  工作流引擎  1.1 我与工作流引擎在第一家公司工作的时候主要任务就是开发OA系统，当然基本都是有工作流的支持，不过当时使用的工作流引擎是公司一些牛人开发的（据说是用一个开源的引擎修改的），名称叫CoreFlow；功能相对Activiti来说比较弱，但是能满足日常的使用，当然也有不少的问题所">
<meta property="og:type" content="article">
<meta property="og:title" content="Activiti工作流引擎使用">
<meta property="og:url" content="https://www.itchina.top/2018/04/20/Activiti工作流引擎使用/index.html">
<meta property="og:site_name" content="LErry">
<meta property="og:description" content="Activiti工作流引擎使用1.简单介工作流引擎与Activiti对于工作流引擎的解释请参考百度百科：  工作流引擎  1.1 我与工作流引擎在第一家公司工作的时候主要任务就是开发OA系统，当然基本都是有工作流的支持，不过当时使用的工作流引擎是公司一些牛人开发的（据说是用一个开源的引擎修改的），名称叫CoreFlow；功能相对Activiti来说比较弱，但是能满足日常的使用，当然也有不少的问题所">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="http://static.open-
open.com/lib/uploadImg/20121017/20121017155144_803.png">
<meta property="og:image" content="http://static.open-
open.com/lib/uploadImg/20121017/20121017155145_849.png">
<meta property="og:image" content="http://static.open-
open.com/lib/uploadImg/20121017/20121017155146_668.png">
<meta property="og:image" content="http://static.open-
open.com/lib/uploadImg/20121017/20121017155147_20.png">
<meta property="og:image" content="http://static.open-
open.com/lib/uploadImg/20121017/20121017155147_321.png">
<meta property="og:updated_time" content="2018-04-25T12:25:55.582Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Activiti工作流引擎使用">
<meta name="twitter:description" content="Activiti工作流引擎使用1.简单介工作流引擎与Activiti对于工作流引擎的解释请参考百度百科：  工作流引擎  1.1 我与工作流引擎在第一家公司工作的时候主要任务就是开发OA系统，当然基本都是有工作流的支持，不过当时使用的工作流引擎是公司一些牛人开发的（据说是用一个开源的引擎修改的），名称叫CoreFlow；功能相对Activiti来说比较弱，但是能满足日常的使用，当然也有不少的问题所">
<meta name="twitter:image" content="http://static.open-
open.com/lib/uploadImg/20121017/20121017155144_803.png">
    

    
        <link rel="alternate" href="/atom.xml" title="LErry" type="application/atom+xml" />
    

    
        <link rel="icon" href="/css/images/shortcut_icon.png" />
    

    <link rel="stylesheet" href="/libs/font-awesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="/libs/open-sans/styles.css">
    <link rel="stylesheet" href="/libs/source-code-pro/styles.css">

    <link rel="stylesheet" href="/css/style.css">

    <script src="/libs/jquery/2.1.3/jquery.min.js"></script>
    
    
        <link rel="stylesheet" href="/libs/lightgallery/css/lightgallery.min.css">
    
    
        <link rel="stylesheet" href="/libs/justified-gallery/justifiedGallery.min.css">
    
    
    
    


</head>

<body>
    <div id="container">
        <header id="header">
    <div id="header-main" class="header-inner">
        <div class="outer">
            <a href="/" id="logo">
                <i class="logo"></i>
                <span class="site-title">LErry</span>
            </a>
            <nav id="main-nav">
                
                    <a class="main-nav-link" href="/.">主页</a>
                
                    <a class="main-nav-link" href="/freebooks">书籍</a>
                
                    <a class="main-nav-link" href="/tags">标签</a>
                
                    <a class="main-nav-link" href="/archives">归档</a>
                
                    <a class="main-nav-link" href="/aboutme">关于</a>
                
            </nav>
            
                
                <nav id="sub-nav">
                    <div class="profile" id="profile-nav">
                        <a id="profile-anchor" href="javascript:;">
                            <img class="avatar" src="/css/images/avatar.png" />
                            <i class="fa fa-caret-down"></i>
                        </a>
                    </div>
                </nav>
            
            <div id="search-form-wrap">

    <form class="search-form">
        <input type="text" class="ins-search-input search-form-input" placeholder="搜索" />
        <button type="submit" class="search-form-submit"></button>
    </form>
    <div class="ins-search">
    <div class="ins-search-mask"></div>
    <div class="ins-search-container">
        <div class="ins-input-wrapper">
            <input type="text" class="ins-search-input" placeholder="想要查找什么..." />
            <span class="ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: '文章',
            PAGES: '页面',
            CATEGORIES: '分类',
            TAGS: '标签',
            UNTITLED: '(未命名)',
        },
        ROOT_URL: '/',
        CONTENT_URL: '/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
<script src="/js/insight.js"></script>

</div>
        </div>
    </div>
    <div id="main-nav-mobile" class="header-sub header-inner">
        <table class="menu outer">
            <tr>
                
                    <td><a class="main-nav-link" href="/.">主页</a></td>
                
                    <td><a class="main-nav-link" href="/freebooks">书籍</a></td>
                
                    <td><a class="main-nav-link" href="/tags">标签</a></td>
                
                    <td><a class="main-nav-link" href="/archives">归档</a></td>
                
                    <td><a class="main-nav-link" href="/aboutme">关于</a></td>
                
                <td>
                    
    <div class="search-form">
        <input type="text" class="ins-search-input search-form-input" placeholder="搜索" />
    </div>

                </td>
            </tr>
        </table>
    </div>
</header>

        <div class="outer">
            
                

<aside id="profile">
    <div class="inner profile-inner">
        <div class="base-info profile-block">
            <img id="avatar" src="/css/images/avatar.png" />
            <h2 id="name">LErry Li</h2>
            <h3 id="title">知我者谓我心忧，不知我者谓我何求</h3>
            <span id="location"><i class="fa fa-map-marker"></i>Shanghai, China</span>
            <a id="follow" target="_blank" href="https://github.com/lerry903">关注我</a>
        </div>
        <div class="article-info profile-block">
            <div class="article-info-block">
                65
                <span>文章</span>
            </div>
            <div class="article-info-block">
                54
                <span>标签</span>
            </div>
        </div>
        
        <div class="profile-block social-links">
            <table>
                <tr>
                    
                    
                    <td>
                        <a href="https://github.com/lerry903" target="_blank" title="github" class=tooltip>
                            <i class="fa fa-github"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="mailto:lerryli@foxmail.com" target="_blank" title="envelope" class=tooltip>
                            <i class="fa fa-envelope"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="http://wpa.qq.com/msgrd?v=3&uin=824444270&site=qq&menu=yes" target="_blank" title="qq" class=tooltip>
                            <i class="fa fa-qq"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="https://weibo.com/5941010376" target="_blank" title="weibo" class=tooltip>
                            <i class="fa fa-weibo"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="/atom.xml" target="_blank" title="rss" class=tooltip>
                            <i class="fa fa-rss"></i>
                        </a>
                    </td>
                    
                </tr>
            </table>
        </div>
        
    </div>
</aside>

            
            <section id="main"><article id="post-Activiti工作流引擎使用" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 class="article-title" itemprop="name">
            Activiti工作流引擎使用
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Activiti工作流引擎使用/">
            <time datetime="2018-04-19T16:34:21.414Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
                        
                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <h1 id="Activiti工作流引擎使用"><a href="#Activiti工作流引擎使用" class="headerlink" title="Activiti工作流引擎使用"></a>Activiti工作流引擎使用</h1><h1 id="1-简单介工作流引擎与Activiti"><a href="#1-简单介工作流引擎与Activiti" class="headerlink" title="1.简单介工作流引擎与Activiti"></a>1.简单介工作流引擎与Activiti</h1><p>对于工作流引擎的解释请参考百度百科： <a href="http://baike.baidu.com/view/1636259.htm" target="_blank" rel="noopener"> 工作流引擎 </a></p>
<h3 id="1-1-我与工作流引擎"><a href="#1-1-我与工作流引擎" class="headerlink" title="1.1 我与工作流引擎"></a>1.1 我与工作流引擎</h3><p>在第一家公司工作的时候主要任务就是开发OA系统，当然基本都是有工作流的支持，不过当时使用的工作流引擎是公司一些牛人开发的（据说是用一个开源的引擎修改的），名<br>称叫CoreFlow；功能相对Activiti来说比较弱，但是能满足日常的使用，当然也有不少的问题所以后来我们只能修改引擎的代码打补丁。</p>
<p>现在是我工作的第二家公司，因为要开发ERP、OA等系统需要使用工作流，在项目调研阶段我先搜索资料选择使用哪个 <strong> 开源 </strong><br>工作流引擎，最终确定了Activiti5并基于公司的架构做了一些DEMO。</p>
<h3 id="1-2-Activiti与JBPM5？"><a href="#1-2-Activiti与JBPM5？" class="headerlink" title="1.2 Activiti与JBPM5？"></a>1.2 Activiti与JBPM5？</h3><p>对于Activiti、jBPM4、jBPM5我们应该如何选择，在InfoQ上有一篇文章写的很好，从大的层面比较各个引擎之间的差异，请参考文章： <a href="http://www.infoq.com/cn/articles/rh-
jbpm5-activiti5" target="_blank" rel="noopener"><br>纵观jBPM：从jBPM3到jBPM5以及Activiti5 </a></p>
<h3 id="1-3-Activiti资料"><a href="#1-3-Activiti资料" class="headerlink" title="1.3 Activiti资料"></a>1.3 Activiti资料</h3><ul>
<li><p>官网： <a href="http://www.activiti.org/" target="_blank" rel="noopener"> http://www.activiti.org/ </a></p>
</li>
<li><p>下载： <a href="http://www.activiti.org/download.html" target="_blank" rel="noopener"> http://www.activiti.org/download.html </a></p>
</li>
<li><p>版本：Activiti的版本是从 <strong> 5 </strong> 开始的，因为Activiti是使用jBPM4的源码； <strong> 版本发布 </strong> ：两个月发布一次。 </p>
</li>
<li><p>Eclipse Plugin: <a href="http://activiti.org/designer/update/" target="_blank" rel="noopener"> http://activiti.org/designer/update/ </a></p>
</li>
<li><p>Activit中文群：5435716 </p>
</li>
</ul>
<h2 id="2-初次使用遇到问题收集"><a href="#2-初次使用遇到问题收集" class="headerlink" title="2.初次使用遇到问题收集"></a>2.初次使用遇到问题收集</h2><p>因为Activiti刚刚退出不久所以资料比较 <strong> 空缺 </strong> ，中文资料更是少的 <strong> 可怜 </strong> ，所以开始的时候一头雾水（虽然之前用过工作流，但是感觉<br>差距很多），而且官方的手册还不是很全面；所以我把我在学习使用的过程遇到的一些疑问都罗列出来分享给大家；以下几点是我遇到和想到的，如果你还有什么疑问可以在评论<br>中和我交流再补充。</p>
<h3 id="2-1-部署流程图后中文乱码"><a href="#2-1-部署流程图后中文乱码" class="headerlink" title="2.1 部署流程图后中文乱码"></a>2.1 部署流程图后中文乱码</h3><p><strong> 乱码 </strong> 是一直缠绕着国人的问题，之前各个技术、工具出现乱码的问题写过很多文章，这里也不例外……，Activiti的乱码问题在流程图中。 </p>
<p>流程图的乱码如下图所示：</p>
<p><img src="http://static.open-
open.com/lib/uploadImg/20121017/20121017155144_803.png" alt="Activiti工作流引擎使用"></p>
<p>解决办法有两种：</p>
<h4 id="2-1-1-修改源代码方式"><a href="#2-1-1-修改源代码方式" class="headerlink" title="2.1.1 修改源代码方式"></a>2.1.1 修改源代码方式</h4><p>修改源码</p>
<pre><code>org.activiti.engine.impl.bpmn.diagram.ProcessDiagramCanvas
</code></pre><p>在构造方法</p>
<pre><code>public ProcessDiagramCanvas(int width, int height)
</code></pre><p>中有一行代码是设置字体的，默认是用  <strong> Arial </strong> 字体，这就是乱码产生的原因，把字改为本地的中文字体即可，例如：</p>
<pre><code>Font font = new Font(&quot;WenQuanYi Micro Hei&quot;, Font.BOLD, 11);
</code></pre><p>当然如果你有配置文件读取工具那么可以设置在*.properties文件中，我就是这么做的：</p>
<pre><code>Font font = new Font(PropertyFileUtil.get(&quot;activiti.diagram.canvas.font&quot;), Font.BOLD, 11);
</code></pre><h4 id="2-1-2-使用压缩包方式部署"><a href="#2-1-2-使用压缩包方式部署" class="headerlink" title="2.1.2 使用压缩包方式部署"></a>2.1.2 使用压缩包方式部署</h4><p>Activiti支持部署*.bpmn20.xml、bar、zip格式的流程定义。</p>
<p>使用Activit Deisigner工具设计流程图的时候会有三个类型的文件:</p>
<ul>
<li><p>.activiti设计工具使用的文件 </p>
</li>
<li><p>.bpmn20.xml设计工具自动根据.activiti文件生成的xml文件 </p>
</li>
<li><p>.png流程图图片 </p>
</li>
</ul>
<p>解决办法就是把xml文件和图片文件同时部署，因为在单独部署xml文件的时候Activiti会自动生成一张流程图的图片文件，但是这样在使用的时候坐标和图片对应<br>不起来……</p>
<p>所以把xml和图片同时部署的时候Activiti自动关联xml和图片，当需要获取图片的时候直接返回部署时压缩包里面的图片文件，而不是Activiti自动生成<br>的图片文件</p>
<h5 id="2-1-2-1-使用工具打包Bar文件"><a href="#2-1-2-1-使用工具打包Bar文件" class="headerlink" title="2.1.2.1 使用工具打包Bar文件"></a>2.1.2.1 使用工具打包Bar文件</h5><p>右键项目名称然后点击“Create deployment artifacts”，会在src目录中创建 <strong> deployment </strong><br>文件夹，里面包含*.bar文件.</p>
<h5 id="2-1-2-2-使用Ant脚本打包Zip文件"><a href="#2-1-2-2-使用Ant脚本打包Zip文件" class="headerlink" title="2.1.2.2 使用Ant脚本打包Zip文件"></a>2.1.2.2 使用Ant脚本打包Zip文件</h5><p>这也是我们采用的办法，你可以手动选择xml和png打包成zip格式的文件，也可以像我们一样采用ant target的方式打包这两个文件。</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project name=&quot;foo&quot;&gt;

    &lt;property name=&quot;workflow.definition&quot; value=&quot;foo-common-core/src/main/resources/diagrams&quot; /&gt;
    &lt;property name=&quot;workflow.deployments&quot; value=&quot;foo-common-core/src/main/resources/deployments&quot; /&gt;

&lt;target name=&quot;workflow.package.oa.leave&quot;&gt;
        &lt;echo&gt;打包流程定义及流程图::OA-请假&lt;/echo&gt;
        &lt;zip destfile=&quot;${workflow.deployments}/oa/leave.zip&quot; basedir=&quot;${workflow.definition}/oa/leave&quot; update=&quot;true&quot;
            includes=&quot;*.xml,*.png&quot; /&gt;
    &lt;/target&gt;
&lt;/project&gt;
</code></pre><p>这样当修改流程定义文件后只要运行ant命令就可以打包了：</p>
<pre><code>ant workflow.package.oa.leave
</code></pre><p>现在部署bar或者zip文件查看流程图图片就不是乱码了，而是你的压缩包里面的png文件。</p>
<h3 id="2-2-使用引擎提供的Form还是自定义业务Form"><a href="#2-2-使用引擎提供的Form还是自定义业务Form" class="headerlink" title="2.2 使用引擎提供的Form还是自定义业务Form"></a>2.2 使用引擎提供的Form还是自定义业务Form</h3><h4 id="2-2-1-引擎提供的Form"><a href="#2-2-1-引擎提供的Form" class="headerlink" title="2.2.1 引擎提供的Form"></a>2.2.1 引擎提供的Form</h4><p>定义表单的方式在每个Task标签中定义 <strong> extensionElements </strong> 和 <strong> activiti:formProperty </strong><br>即可，到达这个节点的时候可以通过API读取表单元素。</p>
<p>Activiti官方的例子使用的就是在流程定义中设置每一个节点显示什么样的表单哪些字段需要显示、哪些字段只读、哪些字段必填。</p>
<p>但是这种方式仅仅适用于比较简单的流程，对于稍微复杂或者页面需要业务逻辑的判断的情况就不适用了。</p>
<p>对于数据的保存都是在引擎的表中，不利于和其他表的关联、对整个系统的规划也不利！</p>
<h4 id="2-2-2-自定义业务Form"><a href="#2-2-2-自定义业务Form" class="headerlink" title="2.2.2 自定义业务Form"></a>2.2.2 自定义业务Form</h4><p>这种方式应该是大家用的最多的了，因为一般的业务系统业务逻辑都会比较复杂，而且数据库中很多表都会有依赖关系，表单中有很多状态判断。</p>
<p>例如我们的系统适用jQuery UI作为UI，有很多javascript代码，页面的很多操作需要特殊处理（例如：多个选项的互斥、每个节点根据类型和操作人显示<br>不同的按钮）；基本每个公司都有一套自己的UI风格，要保持多个系统的操作习惯一致只能使用自定义表单才能满足。</p>
<h3 id="2-3-业务和流程的关联方式"><a href="#2-3-业务和流程的关联方式" class="headerlink" title="2.3 业务和流程的关联方式"></a>2.3 业务和流程的关联方式</h3><p>这个问题在群里面很多人都问过，这也是我刚刚开始迷惑的地方；</p>
<p>后来看了以下API发现RuntimeService有两个方法：</p>
<h3 id="2-3-1-startProcessInstanceByKey"><a href="#2-3-1-startProcessInstanceByKey" class="headerlink" title="2.3.1 startProcessInstanceByKey"></a>2.3.1 startProcessInstanceByKey</h3><p>javadoc对其说明：</p>
<pre><code>startProcessInstanceByKey(String processDefinitionKey, Map variabes) 
          Starts a new process instance in the latest version of the process definition with the given key
</code></pre><p>其中 <strong> businessKey </strong><br>就是业务ID，例如要申请请假，那么先填写登记信息，然后（保存+启动流程），因为请假是单独设计的数据表，所以保存后得到实体ID就可以把它传给 <strong><br>processInstanceBusinessKey </strong> 方法启动流程。当需要根据businessKey查询流程的时候就可以通过API查询:</p>
<pre><code>runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(processInstanceBusinessKey, processDefinitionKey);
</code></pre><p>建  <strong> 议数据库冗余设计 </strong> ：在业务表设计的时候添加一列：  <strong> PROCESS_INSTANCE_ID varchar2(64) </strong><br>，在流程启动之后把流程ID更新到业务表中，这样不管从业务还是流程都可以查询到对方！</p>
<p><strong> 特别说明： </strong> 此方法启动时自动选择最新版本的流程定义。 </p>
<h3 id="2-3-2-startProcessInstanceById"><a href="#2-3-2-startProcessInstanceById" class="headerlink" title="2.3.2 startProcessInstanceById"></a>2.3.2 startProcessInstanceById</h3><p>javadoc对其说明：</p>
<pre><code>startProcessInstanceById(String processDefinitionId, String businessKey, Map variables) 
          Starts a new process instance in the exactly specified version of the process definition with the given id.
</code></pre><p><strong> processDefinitionId </strong> ：这个参数的值可以通过 <strong> repositoryService.createProcessDefinitionQuery() </strong> 方法查询，对应数据库： <strong> ACT_RE_PROCDEF </strong> ；每次部署一次流程定义就会添加一条数据，同名的版本号累加。 </p>
<p><strong> 特别说明： </strong> 此可以指定不同版本的流程定义，让用户多一层选择。 </p>
<h3 id="2-3-3-如何选择"><a href="#2-3-3-如何选择" class="headerlink" title="2.3.3 如何选择"></a>2.3.3 如何选择</h3><p>建议使用 <strong> startProcessInstanceByKey </strong> ，特殊情况需要使用以往的版本选择使用 <strong><br>startProcessInstanceById </strong> 。</p>
<h3 id="2-4-同步用户数据"><a href="#2-4-同步用户数据" class="headerlink" title="2.4 同步用户数据"></a>2.4 同步用户数据</h3><p>这个问题也是比较多的人询问过，Activiti支持对任务分配到：指定人、指定组、两者组合，而这些人和组的信息都保存在 <strong> ACT_ID.. </strong> 表中，有<br>自己的用户和组(角色)管理让很多人不知所措了；原因是因为每个系统都会存在一个权限管理模块（维护：用户、部门、角色、授权），不知道该怎么和Activiti同步<br>。</p>
<h4 id="2-4-1-建议处理方式"><a href="#2-4-1-建议处理方式" class="headerlink" title="2.4.1 建议处理方式"></a>2.4.1 建议处理方式</h4><p>Activiti有一个 <strong> IdentityService </strong> 接口，通过这个接口可以操控Activiti的ACT_ID_*表的数据，一般的做法是用业务<br>系统的权限管理模块维护用户数据，当进行CRUD操作的时候在原有业务逻辑后面添加同步到Activiti的代码；例如添加一个用户时同步Activiti<br>User的代码片段：</p>
<pre><code>/**
 * 保存用户信息 并且同步用户信息到activiti的identity.User，同时设置角色
 * @param user
 * @param roleIds
 */
public void saveUser(User user, List&lt;Long&gt; roleIds, boolean synToActiviti) {
    accountManager.saveEntity(user);
    String userId = user.getId().toString();

    if (synToActiviti) {
        List&lt;org.activiti.engine.identity.User&gt; activitiUsers = identityService.createUserQuery().userId(userId).list();
        if (activitiUsers.size() == 1) {
            //更新信息
            org.activiti.engine.identity.User activitiUser = activitiUsers.get(0);
            activitiUser.setFirstName(user.getName());
            activitiUser.setLastName(&quot;&quot;);
            activitiUser.setPassword(user.getPassword());
            activitiUser.setEmail(user.getEmail());
            identityService.saveUser(activitiUser);

            // 删除用户的membership
            List&lt;Group&gt; activitiGroups = identityService.createGroupQuery().groupMember(userId).list();
            for (Group group : activitiGroups) {
                identityService.deleteMembership(userId, group.getId());
            }

            // 添加membership
            for (Long roleId : roleIds) {
                Role role = roleManager.getEntity(roleId);
                identityService.createMembership(userId, role.getEnName());
            }

        } else {
            org.activiti.engine.identity.User newUser = identityService.newUser(userId);
            newUser.setFirstName(user.getName());
            newUser.setLastName(&quot;&quot;);
            newUser.setPassword(user.getPassword());
            newUser.setEmail(user.getEmail());
            identityService.saveUser(newUser);

            // 添加membership
            for (Long roleId : roleIds) {
                Role role = roleManager.getEntity(roleId);
                identityService.createMembership(userId, role.getEnName());
            }
        }
    }

}
</code></pre><p>删除操作也和这个类似！</p>
<p>不管从业务系统维护用户还是从Activiti维护，肯定要确定一方，然后CRUD的时候同步到对方，如果需要同步多个子系统那么可以再调用WebService实现<br>。</p>
<h3 id="2-5-流程图设计工具用什么"><a href="#2-5-流程图设计工具用什么" class="headerlink" title="2.5 流程图设计工具用什么"></a>2.5 流程图设计工具用什么</h3><p>Activiti提供了两个流程设计工具，但是面向对象不同。</p>
<ul>
<li><p>Activiti Modeler，面向业务人员，使用开源的BPMN设计工具 <a href="http://www.signavio.com/en.html" target="_blank" rel="noopener"> Signavio </a> ，使用BPMN描述业务流程图 </p>
</li>
<li><p>Eclipse Designer，面向开发人员，Eclipse的插件，可以让开发人员定制每个节点的属性（ID、Name、Listener、Attr等） </p>
</li>
</ul>
<h4 id="2-5-1-我们的方式"><a href="#2-5-1-我们的方式" class="headerlink" title="2.5.1 我们的方式"></a>2.5.1 我们的方式</h4><p>可能你会惊讶，因为我们没有使用Activiti Modeler，我们认为用Viso已经能表达流程图的意思了，而且项目经理也是技术出身，和开发人员也容易沟通。</p>
<p>目前这个项目是第一个使用Activiti的，开始我们在需求调研阶段使用Viso设计流程图，利用 <a href="http://wiki.mbalib.com/wiki/%E6%B3%B3%E9%81%93%E6%B5%81%E7%A8%8B%E5%9B%BE" target="_blank" rel="noopener"> 泳道流程图
</a><br>设计和客户沟通，确定后由负责流程的开发人员用Eclipse Designer设计得到bpmn20.xml，最后部署。</p>
<h3 id="2-6-Eclipse-Designer存在的问题"><a href="#2-6-Eclipse-Designer存在的问题" class="headerlink" title="2.6 Eclipse Designer存在的问题"></a>2.6 Eclipse Designer存在的问题</h3><p>这个插件有一个很讨厌的Bug一直未修复，安装了插件后Eclipse的复制和粘帖快捷键会被更换为(Ctrl+Insert、Shift+Insert)；Bug描<br>述请见：</p>
<ul>
<li><p><a href="http://forums.activiti.org/en/viewtopic.php?f=8&amp;t=2701" target="_blank" rel="noopener"> Activit Forums中报告的Bug </a></p>
</li>
<li><p><a href="http://jira.codehaus.org/browse/ACT-992" target="_blank" rel="noopener"> Jira的登记 </a></p>
</li>
</ul>
<p>所以最后我们只能单独开一个安装了Eclipse Designer的Eclipse专门用来设计流程图，这样就不影响正常使用Eclipse JAVAEE了。</p>
<h2 id="3-配置"><a href="#3-配置" class="headerlink" title="3.配置"></a>3.配置</h2><h3 id="3-1-集成Spring"><a href="#3-1-集成Spring" class="headerlink" title="3.1 集成Spring"></a>3.1 集成Spring</h3><p>对于和Spring的集成Activiti做的不错，简单配置一些Bean代理即可实现，但是有两个和事务相关的地方要提示：</p>
<ul>
<li><p>配置 <strong> processEngineConfiguration </strong> 的时候属性 <strong> transactionManager </strong> 要使用和业务功能的同一个事务管理Bean，否则事务不同步。 </p>
</li>
<li><p>对于实现了org.activiti.engine.delegate包中的接口的类需要被事务控制的实现类需要被Spring代理，并且添加事务的Annotation或者在xml中配置，例如: </p>
</li>
</ul>
<pre><code>/**
 * 创建缴费流程的时候自动创建实体
 *
 * @author HenryYan
 */
@Service
@Transactional
publicclass CreatePaymentProcessListener implementsExecutionListener {
   ....
}
</code></pre><h2 id="4-使用单元测试"><a href="#4-使用单元测试" class="headerlink" title="4.使用单元测试"></a>4.使用单元测试</h2><p>单元测试均使用Spring的AbstractTransactionalJUnit4SpringContextTests作为SuperClass，并且在测试类<br>添加：</p>
<pre><code>@ContextConfiguration(locations = { &quot;/applicationContext-test.xml&quot;})
@RunWith(SpringJUnit4ClassRunner.class)
</code></pre><p>虽然Activiti也提供了测试的一些超类，但是感觉不好用，所以自己封装了一些方法。</p>
<p>代码请转移： <a href="https://gist.github.com/2182847" target="_blank" rel="noopener"> https://gist.github.com/2182847 </a></p>
<h3 id="4-1-验证流程图设计是否正确"><a href="#4-1-验证流程图设计是否正确" class="headerlink" title="4.1 验证流程图设计是否正确"></a>4.1 验证流程图设计是否正确</h3><p>代码请转移： <a href="https://gist.github.com/2182869" target="_blank" rel="noopener"> https://gist.github.com/2182869 </a></p>
<h3 id="4-2-业务对象和流程关联测试"><a href="#4-2-业务对象和流程关联测试" class="headerlink" title="4.2 业务对象和流程关联测试"></a>4.2 业务对象和流程关联测试</h3><p>代码请转移： <a href="https://gist.github.com/2182973" target="_blank" rel="noopener"> https://gist.github.com/2182973 </a></p>
<h2 id="5-各种状态的任务查询以及和业务对象关联"><a href="#5-各种状态的任务查询以及和业务对象关联" class="headerlink" title="5.各种状态的任务查询以及和业务对象关联"></a>5.各种状态的任务查询以及和业务对象关联</h2><p>我们目前分为4中状态：未签收、办理中、运行中、已完成。</p>
<p>查询到任务或者流程实例后要显示在页面，这个时候需要添加业务数据，最终结果就是业务和流程的并集，请参考 <strong> 6.2 </strong> 。</p>
<h3 id="5-1-未签收-Task"><a href="#5-1-未签收-Task" class="headerlink" title="5.1 未签收(Task)"></a>5.1 未签收(Task)</h3><p>此类任务针对于把Task分配给一个角色时，例如部门领导，因为 <strong> 部门领导 </strong> 角色可以指定多个人所以需要先签收再办理，术语： <strong> 抢占式 </strong></p>
<p>对应的API查询：</p>
<pre><code>/**
 * 获取未签收的任务查询对象
 * @param userId    用户ID
 */
@Transactional(readOnly = true)
publicTaskQuery createUnsignedTaskQuery(String userId) {
    TaskQuery taskCandidateUserQuery = taskService.createTaskQuery().processDefinitionKey(getProcessDefKey())
            .taskCandidateUser(userId);
    returntaskCandidateUserQuery;
}
</code></pre><h3 id="5-2-办理中-Task"><a href="#5-2-办理中-Task" class="headerlink" title="5.2 办理中(Task)"></a>5.2 办理中(Task)</h3><p>此类任务数据类源有两种:</p>
<ul>
<li><p>签收后的，5.1中签收后就应该为办理中状态 </p>
</li>
<li><p>节点指定的是具体到一个人，而不是角色 </p>
</li>
</ul>
<p>对应的API查询：</p>
<pre><code>/**
 * 获取正在处理的任务查询对象
 * @param userId    用户ID
 */
@Transactional(readOnly = true)
publicTaskQuery createTodoTaskQuery(String userId) {
    TaskQuery taskAssigneeQuery = taskService.createTaskQuery().processDefinitionKey(getProcessDefKey()).taskAssignee(userId);
    returntaskAssigneeQuery;
}
</code></pre><h3 id="5-3-运行中-ProcessInstance"><a href="#5-3-运行中-ProcessInstance" class="headerlink" title="5.3 运行中(ProcessInstance)"></a>5.3 运行中(ProcessInstance)</h3><p>说白了就是没有结束的流程，所有参与过的人都应该可以看到这个实例，但是Activiti的API没有可以通过用户查询的方法，这个只能自己用hack的方式处理了，<br>我目前还没有处理。</p>
<p>从表 <strong> ACT_RU_EXECUTION </strong> 中查询数据。</p>
<p>对应的API查询：</p>
<pre><code>/**
 * 获取未经完成的流程实例查询对象
 * @param userId    用户ID
 */
@Transactional(readOnly = true)
publicProcessInstanceQuery createUnFinishedProcessInstanceQuery(String userId) {
    ProcessInstanceQuery unfinishedQuery = runtimeService.createProcessInstanceQuery().processDefinitionKey(getProcessDefKey())
            .active();
    returnunfinishedQuery;
}
</code></pre><h3 id="5-4-已完成-HistoricProcessInstance"><a href="#5-4-已完成-HistoricProcessInstance" class="headerlink" title="5.4 已完成(HistoricProcessInstance)"></a>5.4 已完成(HistoricProcessInstance)</h3><p>已经结束的流程实例。</p>
<p>从表 <strong> ACT_HI_PROCINST </strong> 中查询数据。</p>
<pre><code>/**
 * 获取已经完成的流程实例查询对象
 * @param userId    用户ID
 */
@Transactional(readOnly = true)
publicHistoricProcessInstanceQuery createFinishedProcessInstanceQuery(String userId) {
    HistoricProcessInstanceQuery finishedQuery = historyService.createHistoricProcessInstanceQuery()
            .processDefinitionKey(getProcessDefKey()).finished();
    returnfinishedQuery;
}
</code></pre><h3 id="5-5-查询时和业务关联"><a href="#5-5-查询时和业务关联" class="headerlink" title="5.5 查询时和业务关联"></a>5.5 查询时和业务关联</h3><p>提示：之前在业务对象添加了 <strong> PROCESS_INSTANCE_ID </strong> 字段</p>
<p>思路：现在可以利用这个字段查询了，不管是Task还是ProcessInstance都可以得到流程实例ID，可以根据流程实例ID查询实体然后把流程对象设置到实<br>体的一个属性中由Action或者Controller输出到前台。</p>
<p>代码请参考： <a href="https://gist.github.com/2183557" target="_blank" rel="noopener"> https://gist.github.com/2183557 </a></p>
<h2 id="6-UI及截图"><a href="#6-UI及截图" class="headerlink" title="6.UI及截图"></a>6.UI及截图</h2><p>结合实际业务描述一个业务从开始到结束的过程，对于迷惑的同学看完豁然开朗了；这里使用请假作为例子。</p>
<h3 id="6-1-单独一个列表负责申请"><a href="#6-1-单独一个列表负责申请" class="headerlink" title="6.1 单独一个列表负责申请"></a>6.1 单独一个列表负责申请</h3><p>这样的好处是申请和流程办理分离开处理，列表显示未启动流程的请假记录（数据库PROCESS_INSTANCE_ID为空）。</p>
<p>申请界面的截图：</p>
<p><img src="http://static.open-
open.com/lib/uploadImg/20121017/20121017155145_849.png" alt="Activiti工作流引擎使用"></p>
<h3 id="6-2-流程状态"><a href="#6-2-流程状态" class="headerlink" title="6.2 流程状态"></a>6.2 流程状态</h3><p><img src="http://static.open-
open.com/lib/uploadImg/20121017/20121017155146_668.png" alt="Activiti工作流引擎使用"></p>
<h3 id="6-3-流程跟踪"><a href="#6-3-流程跟踪" class="headerlink" title="6.3 流程跟踪"></a>6.3 流程跟踪</h3><p>图片方式显示当前节点：</p>
<p><img src="http://static.open-
open.com/lib/uploadImg/20121017/20121017155147_20.png" alt="Activiti工作流引擎使用"></p>
<p>列表形式显示流程流转过程:</p>
<p><img src="http://static.open-
open.com/lib/uploadImg/20121017/20121017155147_321.png" alt="Activiti工作流引擎使用"></p>
<h4 id="6-3-1-当前节点定位JS"><a href="#6-3-1-当前节点定位JS" class="headerlink" title="6.3.1 当前节点定位JS"></a>6.3.1 当前节点定位JS</h4><p><strong> Java </strong> 代码请移步： <a href="https://gist.github.com/2183712" target="_blank" rel="noopener"> https://gist.github.com/2183712 </a></p>
<p><strong> Javascript </strong> 思路：先通过Ajax获取当前节点的坐标，在指定位置添加红色边框，然后加载图片。 </p>
<p>代码移步： <a href="https://gist.github.com/2183804" target="_blank" rel="noopener"> https://gist.github.com/2183804 </a></p>
<h2 id="7-开启Logger"><a href="#7-开启Logger" class="headerlink" title="7.开启Logger"></a>7.开启Logger</h2><ol>
<li>添加log4j的jar </li>
<li>设置 <strong> log4j.logger.java.sql </strong> =DEBUG </li>
</ol>
<h2 id="8-结束"><a href="#8-结束" class="headerlink" title="8.结束"></a>8.结束</h2><p>之前就想写这篇文章，现在终于完成了，花费了几个小时，希望能节省你几天的时间。</p>
<p>请读者仔细阅读Activiti的用户手册和Javadoc。  </p>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Activiti工作流引擎使用/#comments" id="sourceId::2018/04/20/Activiti工作流引擎使用/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
        
<nav id="article-nav">
    
        <a href="/2018/04/20/apache调优隐藏版本信息及404重定向/" id="article-nav-newer" class="article-nav-link-wrap">
            <strong class="article-nav-caption">上一篇</strong>
            <div class="article-nav-title">
                
                    apache调优隐藏版本信息及404重定向
                
            </div>
        </a>
    
    
        <a href="/2018/04/20/ActiveMQ笔记(6)：消息延时投递/" id="article-nav-older" class="article-nav-link-wrap">
            <strong class="article-nav-caption">下一篇</strong>
            <div class="article-nav-title">ActiveMQ笔记(6)：消息延时投递</div>
        </a>
    
</nav>


    
</article>


    
    
        <section id="comments">
    <div id="SOHUCS" sid="2018/04/20/Activiti工作流引擎使用/"></div>
</section>
    

</section>
            
                
<aside id="sidebar">
   
        
    <div class="widget-wrap">
        <h3 class="widget-title">最新文章</h3>
        <div class="widget">
            <ul id="recent-post" class="no-thumbnail">
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/IDE/">IDE</a></p>
                            <p class="item-title"><a href="/2018/04/20/项目相关的CVS操作/" class="title">项目相关的CVS操作</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.467Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/J2EE/">J2EE</a></p>
                            <p class="item-title"><a href="/2018/04/20/图片转换PDF文件/" class="title">图片转换PDF文件</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.449Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/Spring/">Spring</a></p>
                            <p class="item-title"><a href="/2018/04/20/使用 Spring Data JPA 简化 JPA 开发/" class="title">使用 Spring Data JPA 简化 JPA 开发</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.448Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"></p>
                            <p class="item-title"><a href="/2018/04/20/通过Ajax进行POST提交JSON类型的数据到SpringMVC Controller的方法/" class="title">通过Ajax进行POST提交JSON类型的数据到SpringMVC Controller的方法</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.448Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"></p>
                            <p class="item-title"><a href="/2018/04/20/面试感悟----一名3年工作经验的程序员应该具备的技能/" class="title">面试感悟----一名3年工作经验的程序员应该具备的技能</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.447Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
            </ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">分类</h3>
        <div class="widget">
            <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/ActiveMQ/">ActiveMQ</a><span class="category-list-count">7</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/ExtJs/">ExtJs</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Git/">Git</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/IDE/">IDE</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/J2EE/">J2EE</a><span class="category-list-count">7</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/J2EE/Spring/">Spring</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Redis/">Redis</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Spring/">Spring</a><span class="category-list-count">21</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/cnn图片数据处理、显示/">cnn图片数据处理、显示</a><span class="category-list-count">1</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/cnn图片数据处理、显示/python数据分析/">python数据分析</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/web前端/">web前端</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库/">数据库</a><span class="category-list-count">3</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/数据库/集群/">集群</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/集群/">集群</a><span class="category-list-count">2</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">归档</h3>
        <div class="widget">
            <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/04/">四月 2018</a><span class="archive-list-count">65</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">标签</h3>
        <div class="widget">
            <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Apache/">Apache</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Docker/">Docker</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Druid/">Druid</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ImageToPDF/">ImageToPDF</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Logstash/">Logstash</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Spring-Boot/">Spring Boot</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/activemq/">activemq</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ajax/">ajax</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/angular/">angular</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cas/">cas</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/exception/">exception</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ext/">ext</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/extjs/">extjs</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/find/">find</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/github/">github</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ide/">ide</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/idea/">idea</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/">java</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javascript/">javascript</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/jboss/">jboss</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/jmx/">jmx</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/jpa/">jpa</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/lombok/">lombok</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mvc/">mvc</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mysql/">mysql</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/numpy/">numpy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/seo/">seo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/server/">server</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/shiro/">shiro</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring/">spring</a><span class="tag-list-count">17</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring-mvc/">spring mvc</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring-boo/">spring-boo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sql-server/">sql server</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/windows/">windows</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/">zookeeper</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/优化/">优化</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/分布式日志/">分布式日志</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/多线程/">多线程</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/工作/">工作</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/异常/">异常</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/异常处理/">异常处理</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/搜索引擎/">搜索引擎</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据分析/">数据分析</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/汉字转拼音/">汉字转拼音</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/版本控制系统/">版本控制系统</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/程序员/">程序员</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/经验/">经验</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/集群/">集群</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/面试/">面试</a><span class="tag-list-count">1</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">标签云</h3>
        <div class="widget tagcloud">
            <a href="/tags/Apache/" style="font-size: 10px;">Apache</a> <a href="/tags/Docker/" style="font-size: 10px;">Docker</a> <a href="/tags/Druid/" style="font-size: 10px;">Druid</a> <a href="/tags/ImageToPDF/" style="font-size: 10px;">ImageToPDF</a> <a href="/tags/Logstash/" style="font-size: 10px;">Logstash</a> <a href="/tags/Spring-Boot/" style="font-size: 10px;">Spring Boot</a> <a href="/tags/activemq/" style="font-size: 18px;">activemq</a> <a href="/tags/ajax/" style="font-size: 10px;">ajax</a> <a href="/tags/angular/" style="font-size: 10px;">angular</a> <a href="/tags/cas/" style="font-size: 10px;">cas</a> <a href="/tags/docker/" style="font-size: 10px;">docker</a> <a href="/tags/exception/" style="font-size: 10px;">exception</a> <a href="/tags/ext/" style="font-size: 14px;">ext</a> <a href="/tags/extjs/" style="font-size: 14px;">extjs</a> <a href="/tags/find/" style="font-size: 10px;">find</a> <a href="/tags/git/" style="font-size: 10px;">git</a> <a href="/tags/github/" style="font-size: 10px;">github</a> <a href="/tags/ide/" style="font-size: 12px;">ide</a> <a href="/tags/idea/" style="font-size: 10px;">idea</a> <a href="/tags/java/" style="font-size: 16px;">java</a> <a href="/tags/javascript/" style="font-size: 12px;">javascript</a> <a href="/tags/jboss/" style="font-size: 10px;">jboss</a> <a href="/tags/jmx/" style="font-size: 10px;">jmx</a> <a href="/tags/jpa/" style="font-size: 10px;">jpa</a> <a href="/tags/linux/" style="font-size: 14px;">linux</a> <a href="/tags/lombok/" style="font-size: 10px;">lombok</a> <a href="/tags/mvc/" style="font-size: 10px;">mvc</a> <a href="/tags/mybatis/" style="font-size: 10px;">mybatis</a> <a href="/tags/mysql/" style="font-size: 12px;">mysql</a> <a href="/tags/nginx/" style="font-size: 10px;">nginx</a> <a href="/tags/numpy/" style="font-size: 10px;">numpy</a> <a href="/tags/seo/" style="font-size: 10px;">seo</a> <a href="/tags/server/" style="font-size: 10px;">server</a> <a href="/tags/shiro/" style="font-size: 12px;">shiro</a> <a href="/tags/spring/" style="font-size: 20px;">spring</a> <a href="/tags/spring-mvc/" style="font-size: 10px;">spring mvc</a> <a href="/tags/spring-boo/" style="font-size: 10px;">spring-boo</a> <a href="/tags/sql-server/" style="font-size: 10px;">sql server</a> <a href="/tags/windows/" style="font-size: 10px;">windows</a> <a href="/tags/zookeeper/" style="font-size: 10px;">zookeeper</a> <a href="/tags/优化/" style="font-size: 12px;">优化</a> <a href="/tags/分布式日志/" style="font-size: 10px;">分布式日志</a> <a href="/tags/多线程/" style="font-size: 10px;">多线程</a> <a href="/tags/工作/" style="font-size: 10px;">工作</a> <a href="/tags/异常/" style="font-size: 10px;">异常</a> <a href="/tags/异常处理/" style="font-size: 10px;">异常处理</a> <a href="/tags/搜索引擎/" style="font-size: 12px;">搜索引擎</a> <a href="/tags/数据分析/" style="font-size: 10px;">数据分析</a> <a href="/tags/汉字转拼音/" style="font-size: 10px;">汉字转拼音</a> <a href="/tags/版本控制系统/" style="font-size: 10px;">版本控制系统</a> <a href="/tags/程序员/" style="font-size: 10px;">程序员</a> <a href="/tags/经验/" style="font-size: 10px;">经验</a> <a href="/tags/集群/" style="font-size: 10px;">集群</a> <a href="/tags/面试/" style="font-size: 10px;">面试</a>
        </div>
    </div>

    
        
    <div class="widget-wrap widget-list">
        <h3 class="widget-title">链接</h3>
        <div class="widget">
            <ul>
                
                    <li>
                        <a href="http://www.baidu.com">百度</a>
                    </li>
                
            </ul>
        </div>
    </div>


    
    <div id="toTop" class="fa fa-angle-up"></div>
</aside>

            
        </div>
        <!--google 底部广告 -->
<div style="width:100%;text-align: center;clear: both;margin-bottom: 20px;" class="hidden-xs">
    <script async src="http://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
    <!-- 博客footer上方的广告 -->
    <ins class="adsbygoogle"
         style="display:block"
         data-ad-client="ca-pub-8254913025324557"
         data-ad-slot="3369473724"
         data-ad-format="auto"></ins>
    <script>
        (adsbygoogle = window.adsbygoogle || []).push({});
    </script>
</div>
<footer id="footer">
    <div class="outer">
        <div id="footer-info" class="inner">
            &copy;2018 - 2018&nbsp; LErry Li &nbsp;版权所有<br>
			<a href="http://www.miitbeian.gov.cn">沪ICP备17054498号-3</a>
        </div>
    </div>
</footer>
        
    
    <script id="cy_cmt_num" src="https://changyan.sohu.com/upload/plugins/plugins.list.count.js?clientId=cytxPSIHr"></script>
    <script charset="utf-8" type="text/javascript" src="https://changyan.sohu.com/upload/changyan.js" ></script>
    <script type="text/javascript">
    window.changyan.api.config({
    appid: 'cytxPSIHr',
    conf: 'prod_3c92d05d8ba4377e48c5fe27c2159761'
    });
    </script>




    
        <script src="/libs/lightgallery/js/lightgallery.min.js"></script>
        <script src="/libs/lightgallery/js/lg-thumbnail.min.js"></script>
        <script src="/libs/lightgallery/js/lg-pager.min.js"></script>
        <script src="/libs/lightgallery/js/lg-autoplay.min.js"></script>
        <script src="/libs/lightgallery/js/lg-fullscreen.min.js"></script>
        <script src="/libs/lightgallery/js/lg-zoom.min.js"></script>
        <script src="/libs/lightgallery/js/lg-hash.min.js"></script>
        <script src="/libs/lightgallery/js/lg-share.min.js"></script>
        <script src="/libs/lightgallery/js/lg-video.min.js"></script>
    
    
        <script src="/libs/justified-gallery/jquery.justifiedGallery.min.js"></script>
    
    



<!-- Custom Scripts -->
<script src="/js/main.js"></script>

    </div>
</body>
</html>